#include <assert.h>
#include <sys/types.h>
#include <unistd.h>
#include "hash.h"
#define _HASHTB_DEBUG_
void* hash_init(uint32_t size, struct hashtb_s* hashtbp, 
              uint32_t (*hash_fn)(unsigned char *s, int size))
{
    assert(size > 0);
    unsigned int i;
    hashtbp = (struct hashtb_s*)malloc(
               size*sizeof(struct elem_s) + sizeof (struct hashtb_s)
              );
    assert(hashtbp != NULL);
#ifdef _HASHFN_TEST_
    hash_count   = (unsigned long int*)malloc(size * sizeof(unsigned long int));
    total_count  = 0;
#endif
    hashtbp->hash_fn = hash_fn;
    if (hashtbp == NULL)
    {
        perror("hashtbp malloc");
        exit(0);
    }
    hashtbp->len = size;
    i = size-1;
    do
    {
        hashtbp->elem[i].priv = &hashtbp->elem[i];
        hashtbp->elem[i].next = NULL;
    }while(i--);
#ifdef _HASHTB_DEBUG_
    printf("hashtb init\n");
    printf("size  is %d\n", size);
#endif
    return hashtbp;
}
int hash_insert(struct elem_s *elemp, struct hashtb_s* hashtbp)
{
    unsigned long int key;
    key = (*(hashtbp->hash_fn))((char *)elemp->data, elemp->data_len);
    key = key % (hashtbp->len);
    elemp->key = key;
    if (hashtbp->elem[key].priv == &hashtbp->elem[key])
    {
        /*
        if is null,the priv should point head;
        */
        hashtbp->elem[key].next = elemp;
        hashtbp->elem[key].next->priv = &hashtbp->elem[key];
        hashtbp->elem[key].priv = elemp;        
        elemp->next = NULL;
    }
    else
    {
        /*
        if is not null,the priv should point last elem
        */
        elemp->priv = hashtbp->elem[key].priv;
        elemp->next = NULL;
        hashtbp->elem[key].priv->next = elemp;
        hashtbp->elem[key].priv = elemp;
        //hashtbp->elem[key].priv->next->priv = hashtbp->elem[key].priv;
        //hashtbp->elem[key].priv       = elemp;
    }
#ifdef _HASHTB_DEBUG_
    /*
    printf("key is %d, value is %s\n",
           hashtbp->elem[key].priv->key,
           (char*)hashtbp->elem[key].priv->data
          );
    */
#endif
}
int hash_search(struct elem_s *elemp, struct hashtb_s* hashtbp)
{
    unsigned long int key;
    struct elem_s *tmp;
    key = (*(hashtbp->hash_fn))((char *)elemp->data, elemp->data_len);
    key = key % (hashtbp->len);
    if (hashtbp->elem[key].priv == &hashtbp->elem[key])
    {
        return 0;
    }
    else
    {
        tmp = hashtbp->elem[key].next;
        do
        {
            if(elemp->data_len == tmp->data_len && 0 == memcmp((char*)tmp->data, (char*)elemp->data,elemp->data_len))
            {
                return 1;
            }
            //tmp = elemp->next;
        }while(tmp = elemp->next);
    }
    return NULL;
}
